using System;
using System.Collections.Generic;
using System.Text;

namespace GuavaData
{
    public class PivotOp : Operator
    {
        // Performs a pivot operation - translates triples into normal rows

        #region Fields
        Operator child;
        public Operator Child
        {
            get { return child; }
            set { child = value; }
        }

        Dictionary<string, string> keyMap;
        public Dictionary<string, string> KeyMap
        {
            get { return keyMap; }
            set { keyMap = value; }
        }

        Dictionary<string, string> foldValues;
        public Dictionary<string, string> FoldValues
        {
            get { return foldValues; }
            set { foldValues = value; }
        }

        string attCol;
        public string AttCol
        {
            get { return attCol; }
            set { attCol = value; }
        }

        string valCol;
        public string ValCol
        {
            get { return valCol; }
            set { valCol = value; }
        }

        string newAlias;
        public string NewAlias
        {
            get { return newAlias; }
            set { newAlias = value; }
        }

        public static bool IsOracle = false;

        #endregion Fields

        public PivotOp(Operator child, Dictionary<string, string> keyMap, Dictionary<string, string> foldValues, string attCol, string valCol, string newAlias)
        {
            this.child = child;
            child.parent = this;
            this.keyMap = keyMap;
            this.foldValues = foldValues;
            this.attCol = attCol;
            this.valCol = valCol;
            this.newAlias = newAlias;

            // Create output schema - make sure that the attCol and valCol columns exist
            Domain.Domain a = null;
            Domain.Domain v = null;

            this.exposedColumns = new List<string>();
            this.exposedDomains = new List<GuavaData.Domain.Domain>();

            for (int i = 0; i < child.exposedColumns.Count; i++)
            {
                if (child.exposedColumns[i] == attCol)
                {
                    a = child.exposedDomains[i];
                }
                else if (child.exposedColumns[i] == valCol)
                {
                    v = child.exposedDomains[i];
                }
                else
                {
                    this.exposedColumns.Add(child.exposedColumns[i]);
                    this.exposedDomains.Add(child.exposedDomains[i]);
                }
            }

            // If a/v is still null, then we didn't find correct columns, and there is an error
            if (a == null)
                throw new Exception("Did not find attribute column " + attCol + " to pivot.");
            if (v == null)
                throw new Exception("Did not find value column " + valCol + " to pivot.");
            Domain.Enumerated e = new GuavaData.Domain.Enumerated(foldValues.Keys);

            // Add the pivoted columns
            foreach (string s in this.FoldValues.Keys)
            {
                this.exposedColumns.Add(foldValues[s]);
                this.exposedDomains.Add(v);
            }
        }

        public string PivotValueList
        {
            get
            {
                var ks = new List<string>(this.foldValues.Keys);

                if (IsOracle)
                {
                    var build = String.Concat("('", ks[0].Split('\"')[1], "' AS " + ks[0]);
                    for (int i = 1; i < ks.Count; i++)
                    {
                        build = String.Concat(build, ", '", ks[i].Split('\"')[1], "' AS " + ks[i]);
                    }
                    build = build + ")";
                    return build;
                }
                else
                {
                    if (ks.Count == 0) return "";
                    var build = String.Concat("([", ks[0], "]");
                    for (int i = 1; i < ks.Count; i++)
                    {
                        build = String.Concat(build, ", [", ks[i], "]");
                    }
                    build = build + ")";
                    return build;
                }
            }
        }

        public override SqlText Visit(Provider qv)
        {
            return qv.Transform(this);
        }
        public override void Visit(Transform t, Command c)
        {
            t.Expand(this, c);
        }

        public override Operator Clone()
        {
            return new PivotOp(this.child.Clone(), this.keyMap, this.foldValues, this.attCol, this.valCol, this.newAlias);
        }

        public override void NotifyChange(Operator old, Operator newOp)
        {
            if (child == old)
            {
                this.child = newOp;
                newOp.parent = this;
            }
        }

        public override void Visit(Channel c, string table)
        {
            c.MapAliases(this, table);
        }

    }
}
